home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ASMVEG4.ZIP / ASMVEG4.TXT next >
Text File  |  1996-12-23  |  15KB  |  282 lines

  1.       Assembly Language for Veggies (And C programmers)      Part 4.
  2.  
  3. Welcome Back...  As I commenced to write part 4, I did what I usually do which
  4. is to re-read over part three.... and hece I found a MISTAKE! <Gasp!>
  5.  
  6. In the section that tells you all about what uses the first 64k of RAM, I said
  7. the area between 0000 and 0100 was used by the interrupt table vectors... now
  8. if one takes 256 and multiplies it by 4 bytes per interrupt one gets 1024.
  9. 1024 in HEX is of course 400 - so the area 0000 - 03FF is ALL used to store
  10. the vectors of the interrupts....  My cincere aplologies for those misled, but
  11. hey, bugs creep into anything!!
  12.  
  13. OK...  on to Edition 4..  What will we look at? <Sits here, makes cup of
  14. coffee, searches a few ASM books, spills coffee, crashes machine, chucks on
  15. the Midnight Oil, hassles users then....> thinks of one largely unknown and
  16. little looked-at area of PC Programming...... the TSR.
  17.  
  18. TSR's are without a doubt the wierdest pieces of software! They rely on bugs,
  19. twists and turns, undoccumented parts of DOS and most of all, they perform
  20. HIDDEN MULTITASKING!!!
  21.  
  22. I'll highlight the situation by taking a simple program as an example...
  23.  
  24. When I'm doing work on my PC, I find myself constantly flipping in and out of
  25. DOS, doing this, that and the other, and soon I begin to lose track of the
  26. time.. I can't be stuffed putting a battery in the clock on the wall (Besides
  27. it never was accurate!) so waaaaaaay back when I was learning ASM I decided to
  28. write a non-interactive TSR that would, as long as I was sitting at the DOS
  29. prompt, display the current time in the top right hand corner of the screen.
  30. The clock was required to vanish when an application was run (to avoid
  31. cluttered screens) and to automaticly re-appear at the sign of the DOS prompt.
  32. CC (Clock in Corner) is the result. CC's source and COM should be inside the
  33. archive that comes with ASMVEG4.
  34.  
  35. Now, some general stuff on how TSR's work.
  36.  
  37. A TSR is just like any other COM program EXCEPT for a few rules..  As you
  38. know, when  a COM program gets loaded, it gets handed all available free RAM,
  39. up to the 640k mark for it's own use.. Same for a TSR...  in fact at load
  40. time, DOS has no idea if a program will be a TSR or not. Now, a TSR does a few
  41. things just a little differently that a normal COM program...  In a normal COM
  42. program, wellyou just begin executing whatever it was the program was writren
  43. for..  a TSR instead has to run an initialization routine that installs
  44. itself into RAM and makes sure DOS knows that that RAM will be in use from then
  45. on. The initialization routine should also set up all the other bits pertinant
  46. to that particular TSR (IE setting up it's hotkey, or looking for the COMports
  47. or whatever..) Finally, the TSR must discard all uneeded RAM and quit to DOS.
  48.  
  49. Because of this loader arrangement the TSR should be coded thus:
  50.  
  51.  
  52.  
  53. --------- program start (CS:0100 at load time)  -----
  54.  
  55. JMP INITIALIZATION      ; go to the initialize routine
  56.  
  57. ---- TSR CODE
  58. ... etc
  59. ---- TSR CODE
  60.  
  61. INITIALIZATION: 
  62. --- init routine
  63. ... etc
  64. --- init routine
  65.  
  66. ----------- Program END -----------
  67.  
  68.  
  69. The initialization routine makes use of a DOS call that lets you quit, yet
  70. leave some RAM marked as Used, so that DOS will leave it alone and move it's
  71. internal referances to where the bottom most free memory location is up to
  72. past the end of your TSR.
  73.  
  74. This function call is called "Terminate & Stay Resident" (No joke) and is
  75. number 031h. (Dos 2.0+ required).
  76.  
  77. One places the ammount of memory to reserve (in paragraphs) into the DX
  78. register then calls INT 021h as per any normal DOS function call. <note: A
  79. paragraph is 16 bytes>
  80.  
  81. A typical sequence of actions for an initialization routine would be to
  82. display a program title screen, set any required interrupt vectors (see next
  83. section), calculate the number of bytes to be left in memory (rounded up, of
  84. course!) and then call function 031.
  85.  
  86. The reason for the initialization routine bieng right at the very END of the
  87. code is that you can tell DOS to only keep memory up to the end of the TSR
  88. code, but BEFORE the initialization code. This means that DOS will discard
  89. your initialization code (which can be as big as you like) and only keep the
  90. TSR bit. These days it pays to keep as little in memory as possible.
  91.  
  92. So we now know how to tell DOS to keep our code in memory without destroying
  93. it, but our code will just sit there and do nothing...  We have to make sure
  94. that our code is regularly executed to do it's work...  for this we have
  95. several methods...
  96.  
  97. As you recall all DOS & BIOS functions are run via INTERRUPTS, and interrupts
  98. are REDIRECTABLE... SO al we have to do is redirect a few interrupts to our
  99. code and off we go..  Perhaps an example will clarify here: Let's say we code
  100. a TSR to come to life upon hitting of the ALT-F10 key..  All keyboard presses
  101. cause an interrupt, so all we do is redirect the interrupt to ourselves, and
  102. bam... every time a key is hit, out routine gets called...  our routine should
  103. replace the BIOS one (easy!) - and should read they key, see if it's ALT-F10,
  104. if so, clear the KB controller and jump to our routine.. if it's not for us,
  105. it should pass back to the original routine (the BIOS one) without clearling
  106. the key from the keyboard buffer (so that the BIOS can re-read & process it).
  107.  
  108. Simple as that!  CC doesn't use the KB, so you may ask how it runs?  Simple
  109. also.. There's an interrupt called the "Idle Loop" interrupt just made for us.
  110. The idle interrupt is called by DOS whict DOS is busy doing nothing... The
  111. idle loop by default normally passes control straight back to DOS, but if we
  112. direct it to ourselves, we basicly get control handed to us WHEN DOS IS NOT
  113. BUSY DOING OTHER THINGS.
  114.  
  115. One time DOS is not busy is when it's waiting for user input at the C:\>
  116. prompt... (it is not busy at other times too, but it's a good start).
  117.  
  118. There's another flag in low memory that indicates for sure if DOS is on the
  119. commandline or not, but CC doesn't bother checking this (could be done later
  120. to improve the program - I leave this to you to try and work out on your OWN..
  121. You need to research the InDos FLAG - Answers in a future ASMVEG!!)
  122.  
  123. The other thing that all TSR's must watch is that they don't try and run under
  124. themselves - take for example if CC was in the middle of displaying the time
  125. and another Idle Interrupt occurred? DISASTER!! so CC has a flag it sets the
  126. first time it's called.... next time round it checks the flag and if it's set,
  127. it quits back to DOS because it knows it's already going... if the flag is
  128. clear it knows it's OK to go to work...  needless to say the last thing CC
  129. does after displaying the time is to clear the flag again.
  130.  
  131. CC's initialization routine gets the current screen mode, and if it's mode 7
  132. assumes a MONO screen...  if it's not 7 it assumes colour...  CC also assumes
  133. an 80 colum mode (hey, I said it was simple!!) and sets a pointer into video
  134. memory accordingly..  
  135.  
  136. CC then does the work of getting and setting interrupt vectors... CC is rather
  137. rude in that it assumes it's the first Idle interrupt user and won't pass on
  138. down the chain (Again, I said it was simple!!). Try to add a pass-on routine
  139. if you're feeling extravigant.. you'd have to use the GETintVector function,
  140. then save that in a variable addressable in the TSR module, then instead of
  141. doing an IRET, you'd have to do a direct JMP to the old address... why not try
  142. this as a real challenge of your knowlegdge.. again, the improved version will
  143. appear in a later ASMVEG to show you the way that I did it...
  144.  
  145. If you don't follow that, take this: assume another program is already making
  146. useif the idle interrupt... CC always does an IRET after bieng called... what
  147. it should do if jump to wherever the old idle interrupt pointed to so that if
  148. there is another program making use of the interrupt, it too will get called.
  149. Take this for example:
  150.  
  151. IDLE INT ---> old TSR ---> original idle int  ---> Back to Caller
  152.  
  153. CC Currently:
  154.  
  155. IDLE INT ---> CC  ---> Back to Caller (original idle int & old TSR are no
  156.                                        longer called - nasty!) 
  157.  
  158. CC Should do:
  159.  
  160. IDLE INT ---> CC ---> old TSR ---> old idle int ---> Back to Caller
  161.  
  162. This way everything behaves.... the simple short term fix is to load CC first,
  163. but what if you get 2 programs that both misbehave in this regard?  OUCH!
  164.  
  165.  
  166. CC then works out how big CC is and goes TSR. just to further balls things up,
  167. CC uses an older way of going TSR that basicly works the same as function 031
  168. but instead runs off INT 027. INT 027 is DOS 1.0 compatible (as this
  169. originally ran under DOS 1.1!!!!). Another option would be to update to the
  170. more compatible 031 function call... again, I leave this to you to experiment
  171. with...
  172.  
  173. The TSR Part of CC....
  174.  
  175. The TSR part of CC begins at the GET_TIME label.. first off, we save ALL
  176. registers.. this is essential so that the main program that was interrupted
  177. doesn't get screwed up by us...
  178.  
  179. CC then checks to see if it's already running and quits if it is... If CC
  180. isn't already running, it sets the flag to say that it now is, gets the time,
  181. saves it in the HOURS, MINUTES, SECONDS variables and gets the screen buffer
  182. address. Next it displays the time, works out the AM/PM stuff (which isn't
  183. perfect - see where I went wrong if you can...remember, the hour between
  184. midnight and 01:00 is AM, the time between noon and 01:00 is pm...). Lastly,
  185. it clears it's busy flag, restores the registers and returns to the main
  186. system. You might say that CC is naughty in directly accessing the video RAM,
  187. but it does it for 2 reasons: The main one is SPEED... if you take too long,
  188. then you'll slow things down by having al these idle interrupts
  189. bottlenecking... the other reason is often not understood...
  190.  
  191. YOU MUST NEVER CALL A DOS FUNCTION FROM INSIDE A TSR!!  NEVER!!! DOS is
  192. not written to be "Re-Entrant". What this means is this: Say DOS is part way
  193. thru something or other (OK this probably doesn't apply for CC, but a hotkeyed
  194. TSR might certainly have this problem) for argumnets sake say DOS is 1/2 way
  195. thru a disk write. If we go calling another DOS routine it'll upset all of
  196. DOS's internal pointers and stuff and when the original routine resumes (ie
  197. when our TSR quits) all of DOS's internal data will be screwed up..  on the
  198. other hand most of the BIOS is quite re-entrant (thus the use of BIOS int 02C
  199. to get time)... in fact when you issue a mode change command, INT 010 calls
  200. itself 12 - 16 times (depending on version)  to reposition the cursor, set the
  201. colours, reprogram the video controllers, etc...!!!
  202.  
  203. This could be bypased with caution, referance to the InDos flag (See above)
  204. and the like, but it's certainly not consistent over all versions of DOS, nor
  205. reliable for all function calls. Best not to take the risk I always say...
  206. That's why TSR's often stuff things up...  Old sidekick's are notorious for
  207. this! The original sidekick uses the timer tick interrupt to see if another
  208. TSR or program has stolen the keyobard interrupt away from sidekick... if it
  209. has, sidekick steals it right back!  the result: you can pop up sidekick, but
  210. your main program suddenly ignores all your keystrokes!!!
  211.  
  212. Sidekick does this by making use of yet another interrupt - the TIMER TICK...
  213. The BIOS generates an interrupt that excecutes once every 18.2 milliseconds
  214. (read about 55 times a second) NO MATTER WHAT. Again, normally this interrupt
  215. returns straight back to the BIOS but we can tap it and thus our TSR will be
  216. called at a constant non-machine speed dependant rate... a LOT of CPU speed
  217. rating programs use this interrupt to derive a constant speed referance by
  218. which to rate things... other TSR's use it as a constant patch to make sure
  219. their TSR gets called regularly (Stuff like mouse drivers, Fax card software
  220. and even multitaskers use this interrupt!)
  221.  
  222.  
  223. A final comment...
  224.  
  225.  
  226. CC could be improved even further....  it could make use of INT 010 and get
  227. the video mode current at that second - and adjust itself if it found itself
  228. in 40 or 132 colum mode... 
  229.  
  230. Also, takethis situation: If CC is run again, it will simply go TSR and steal
  231. a bit more memory.. the old copy of CC won't execute any more, but it will
  232. still sit there in memory (Question: WHY? Answer is in text above)
  233.  
  234. What CC should do in the initialization section is to search RAM for a
  235. pre-existing copy of CC (by doing a <say> 16 byte compare of the first 16
  236. bytes of the copy bieng executed with the first 16 bytes of all possible CS
  237. settings up to (but not including) the current CS..  If no match, no CC
  238. loaded... if a match, CC already resident, so the running copy should abort..
  239.  
  240. As for uninstalling... this is a major patch... first off, CC should make sure
  241. that the idle interrupt still points to the TSR copy of CC (and hasn't been
  242. pinched - if it has uninstall is impossible) then redirect the idleinterrupt
  243. back to the old, original address (another reason for saving te original
  244. address!!), then you need to call the DOS deallocate memory block program and
  245. point it to CC's TSR area...
  246.  
  247. Messy, yes, but can be achieved with a little effort...
  248.  
  249. Most of these mods will appear in a later ASMVEG (read when I get round to
  250. fixing it!!) but for now, print out or read the source code, run the thing and
  251. try it out... I know it doesn't behave 100% with doubledos (tends to pop up at
  252. the wrong time) - under desqview no idea, but probalby needs to be loaded into
  253. a "writes directly to screen - Yes" and "uses own colours - yes" window..
  254. probably won't handle the screen correctly either if you're not in 80x25 mode
  255. at the time, but then again it wasn't written to be a fully blown program...  
  256.  
  257. So what, may you ask, is all this about HIDDEN MULTITASKING  that i was on
  258. about before....  consider this: you're at the DOS prompt... you can run
  259. anything at any time, and yet this program constantly displays the right time
  260. onscreen, and DOS is oblivious to it's existance....  two programs are running
  261. at once, yes? is this not multitasking? ... it's not really, rahter a sort of
  262. task swapping where it runs one program for a bit, then another for a bit,
  263. then swaps back, but it does it fast enough to look like true tasking...
  264. doubleDos is based around the exact same principal.. each time a timer tick
  265. interrupt occurrs some base code inside DD hands control over to the other
  266. window, first restoring all that window's flags & variables etc... next time
  267. it swaps to the other window and sets up that window's setup..  it's alittle
  268. more complex than that, espescially with regard to device sharing, but that's
  269. all that basicly forms the multitasking core.....  on a 386 it's different,
  270. but for a 286 and 8088/8086 this is the ONLY way to task DOS!!
  271.  
  272. Perhaps now you follow why it's referred to as hidden - there's no
  273. Multitasking driver, rather just normal DOS and normal BIOS doing things as
  274. they always do, just bieng twisted about to suit us.... now you see why I said
  275. TSR's were sneaky?
  276.  
  277. f there's interest, I might release some better source for some TSR's
  278. including a pop-up of some description???  I'll have ta see what I can do for
  279. ya's if there's interest...
  280.  
  281. Ok, well go forth and hack! Until ASMVEG5....  .\\erlin
  282.